using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Net.Mail;
using MacomberMap.Common.Internals;
using System.Xml;
using MacomberMap.Common.User_Interfaces.Events;
using MacomberMap.Common.Components;
using MacomberMap.Common.User_Interfaces.Components;
using MacomberMap.Common.Events;
using System.Reflection;

namespace MacomberMap.Common.Logging
{
    /// <summary>
    /// This class holds information on our log
    /// </summary>
    public static class MM_Log
    {
        #region Variable declarations
        /// <summary>Our connection to the system log</summary>
        private static EventLog SystemLog;

        /// <summary>Our connection to the text log</summary>
        private static StreamWriter TextLog;        

        /// <summary>Whether the event log should be used</summary>
        private static bool UseEventLog = false;

        #endregion

        #region Events
        /// <summary>
        /// A delegate to handle event handling
        /// </summary>
        /// <param name="Event">The event that occurred</param>
        public delegate void MM_Event_Delegate(MM_Event Event);

        /// <summary>
        /// A delegate to handle event state changes
        /// </summary>
        /// <param name="Event">The event that occurred</param>
        /// <param name="OldState">The old state of the element</param>
        /// <param name="NewState">The new state of the element</param>
        public delegate void MM_Event_StateChange_Delegate(MM_Event Event, MM_Event.EventStateEnum OldState, MM_Event.EventStateEnum NewState);

        /// <summary>A new event has been added to the system</summary>
        public static event MM_Event_Delegate EventAdded;

        /// <summary>An event has been removed from the system</summary>
        public static event MM_Event_Delegate EventRemoved;

        /// <summary>An element has been updated in the system</summary>
        public static event MM_Event_Delegate EventUpdated;

        /// <summary>An element's state has changed</summary>
        public static event MM_Event_StateChange_Delegate EventStateChanged;
        #endregion

        #region Initialization       
        /// <summary>
        /// Start up the MM Logger
        /// </summary>
        public static void Initialize()
        {
            /*//First, load in our log events file
            XmlDocument xDoc = new XmlDocument();
            xDoc.Load("MacomberMapEvents.xml");                        
            foreach (XmlElement xElem in xDoc.DocumentElement.ChildNodes)
                MM_Overall_Display.EventTypes.Add(XmlConvert.ToInt32(xElem.Attributes["Index"].Value), xElem.Attributes["Description"].Value, new MM_Event_Type(xElem));
            */

            if (UseEventLog)
            {
                if (!EventLog.SourceExists("MM_Loader"))
                    EventLog.CreateEventSource("MM_Loader", "MM_Loader");
                SystemLog = new EventLog("MM_Loader", ".", "MM_Loader");
                SystemLog.WriteEntry("Macomber Map Loader starting up", EventLogEntryType.Information, 0, 0);
            }
            else
            {
                if (!new FileInfo("MM_Loader.log").Exists)
                {
                    TextLog = new StreamWriter("MM_Loader.log", false, Encoding.UTF8);
                    TextLog.WriteLine("Date/Time,Type,Message,Event,Category");
                }
                else
                    try
                    {
                        TextLog = new StreamWriter("MM_Loader.log", true, Encoding.UTF8);
                    }
                    catch (Exception)
                    {
                        //TextLog = new StreamWriter("MM_Loader-" + DateTime.Now.ToString("yyyy-MM-dd_hh-mm-ss") + "-" + Environment.UserName + ".log");
                    }
                TextLog.AutoFlush = true;
                TextLog.WriteLine("{0},{1},{2},{3},{4}", DateTime.Now, "Information", "Macomber Map loader starting up", 0, 0);
            }
        }
        #endregion

        #region Logging routines
        /// <summary>
        /// Log a new event to the system.
        /// </summary>
        /// <param name="NewEvent"></param>
        /// <returns></returns>
        public static UInt64 LogEvent(MM_Event NewEvent)
        {            
            MM_Repository.Events.Add(NewEvent.TEID, NewEvent);
            if (EventAdded != null)
                EventAdded(NewEvent);            
            return NewEvent.TEID;
        }

        /// <summary>
        /// Remove an event from the queue
        /// </summary>
        /// <param name="Event">The event to be removed</param>
        public static void RemoveEvent(MM_Event Event)
        {
            if (MM_Repository.Events.ContainsKey(Event.TEID))
            {
                MM_Repository.Events.Remove(Event.TEID);
                if (EventRemoved != null)
                    EventRemoved(Event);
            }
        }

        /// <summary>
        /// Update an event within the queue
        /// </summary>
        /// <param name="Event"></param>
        public static void UpdateEvent(MM_Event Event)
        {
            if (EventUpdated != null)
                EventUpdated(Event);
        }

        /// <summary>
        /// Update an event's state within the queue
        /// </summary>
        /// <param name="Event">The event to be updated</param>
        /// <param name="OldState">The old state of the event</param>
        /// <param name="NewState">The new state of the event</param>
        public static void UpdateEventState(MM_Event Event, MM_Event.EventStateEnum OldState, MM_Event.EventStateEnum NewState)
        {
            if (EventStateChanged != null)
                EventStateChanged(Event, OldState, NewState);
        }
        #endregion

        #region Logging shut-down
        /// <summary>
        /// Shutdown the log, and e-mail the results to any specified recipients.
        /// </summary>
        public static void ShutdownLog()
        {
            //If we have log recipients, build our log email
            if (MM_Configuration.LogRecipients.Count > 0)
            {
                //Close our text log
                TextLog.Flush();
                TextLog.Close();

                //Set up our mail and headers
                MailMessage OutMessage = new MailMessage();
                OutMessage.From = MM_Configuration.LogSender;
                foreach (MailAddress Recipient in MM_Configuration.LogRecipients)
                    OutMessage.To.Add(Recipient);
                OutMessage.Subject = "Macomber Map Loader Log results from " + MM_Configuration.StartupTime.ToString("MM/dd/yyyy HH:mm:ss") + ".";
                OutMessage.IsBodyHtml = true;
                OutMessage.DeliveryNotificationOptions = DeliveryNotificationOptions.OnFailure;

                //Build the body of our message
                StringBuilder sB = new StringBuilder();
                sB.AppendLine("<HTML>");
                sB.AppendLine("<B>Macomber Map Loader, started on " + MM_Configuration.StartupTime.ToString("MM/dd/yyyy HH:mm:ss") + " by " + Environment.UserDomainName + "\\" + Environment.UserName + " on " + Environment.MachineName + "</B>");
                sB.AppendLine("<TABLE border=\"1\" Width=\"100%\">");


                //Re-open our text log and read it
                using (StreamReader sRd = new StreamReader("MM_Loader.log"))
                {
                    sB.AppendLine("<TR><TH>" + sRd.ReadLine().Replace(",", "</TH><TH>") + "</TH></TR>");
                    while (!sRd.EndOfStream)
                        sB.AppendLine("<TR><TD>" + sRd.ReadLine().Replace(",", "</TD><TD>") + "</TD></TR>");
                    sRd.Close();
                }

                //Write the rest of our log out
                sB.AppendLine("</TABLE>");
                sB.AppendLine("</HTML>");
                OutMessage.Body = sB.ToString();

                //Send the message out
                SmtpClient OutClient = new SmtpClient(MM_Configuration.SMTPServer);
                OutClient.ServicePoint.MaxIdleTime = 1000;
                OutClient.Send(OutMessage);

                //Dispose of everything
                OutMessage.Dispose();
                OutMessage = null;
                OutClient = null;
                GC.Collect();
                GC.GetTotalMemory(true);
            }
        }
        #endregion

    }

}
